package com.cloudshop.service.common.filter;

import com.cloudshop.service.common.enums.RequestEnum;
import com.cloudshop.service.common.log.GlobalAccessLog;
import com.cloudshop.service.common.log.LogManager;
import com.cloudshop.service.common.mq.LogMqSender;
import com.cloudshop.service.common.utils.CheckEmptyUtil;
import com.cloudshop.service.common.utils.IpUtil;
import com.cloudshop.service.common.utils.JwtTokenUtil;
import java.io.IOException;
import java.util.Date;
import java.util.UUID;
import javax.annotation.Resource;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;

/**
 * 全局日志过滤器.
 *
 * @author 宫新程
 * @since 2019/3/29 15:09
 */
@Slf4j
public class GlobalFilter implements Filter {

  @Value("${spring.application.name}")
  private String projectName;

  @Resource private LogMqSender logMqSender;

  @Override
  public void init(FilterConfig filterConfig) throws ServletException {
    log.info(this.getClass().getName() + "init filter ...");
  }

  @Override
  public void doFilter(
      ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
      throws IOException, ServletException {
    HttpServletRequest request = (HttpServletRequest) servletRequest;
    HttpServletResponse response = (HttpServletResponse) servletResponse;

    /* 解决跨域问题. */
    response.setHeader("Access-Control-Allow-Methods", "POST, GET, PUT, OPTIONS, DELETE, PATCH");
    response.setHeader("Access-Control-Max-Age", "3600");
    response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
    response.setHeader(
        "Access-Control-Allow-Headers",
        "Origin, No-Cache, X-Requested-With, If-Modified-Since, Pragma, Last-Modified, "
            + "Cache-Control, Expires, Content-Type, X-E4M-With, userId, token, Authorization");
    response.setHeader("Access-Control-Allow-Credentials", "true");
    // 如果是OPTIONS请求就return 往后执行会到业务代码中 他不带参数会产生异常
    if (request.getMethod().equals("OPTIONS")) {
      return;
    }


    try {
      String hostName = IpUtil.getHostName();
      String httpMethod = request.getMethod();
      String userAgent = request.getHeader(RequestEnum.USER_AGENT.getCode());
      String domainName = request.getHeader(RequestEnum.HOST.getCode());
      String clientIp = IpUtil.getClientIp(request);
      String uri = request.getRequestURI();
      // 从请求 header 中获取requestId, 如果为空，生成新的 requestId, 并将requestId放入request域中
      String requestId = getOrSetRequestId(request);
      // 从请求 header 中获取调用本工程的上一个工程.
      String fromSystem = request.getHeader(RequestEnum.FROM_SYSTEM.getCode());
      // 获取token.
      String token = request.getHeader(RequestEnum.TOKEN.getCode());
      // 将token放入ThreadLocal中
      JwtTokenUtil.setTokenThread(token);
      String userId = "";
      String userName = "";
      if (CheckEmptyUtil.isNotEmpty(token)) {
        userId = JwtTokenUtil.getUserId() + "";
        userName = JwtTokenUtil.getUserName();
      }
      // 设置当前请求信息
      LogManager.filterInit(
          projectName,
          hostName,
          httpMethod,
          requestId,
          userAgent,
          fromSystem,
          domainName,
          clientIp,
          token,
          userId,
          userName,
          uri);

      // 设置响应头
      response.setHeader(RequestEnum.REQUEST_ID.getCode(), requestId);
      filterChain.doFilter(request, response);
    } catch (Exception e) {
      log.error("请求异常!", e);
      LogManager.setHttpStatus(500);
      LogManager.setException(e.getMessage());
      throw e;
    } finally {
      LogManager.setEndTime(new Date());
      GlobalAccessLog accessLog = LogManager.getGlobalAccessLog();
      // 发送mq
      logMqSender.sendLogMq(accessLog);
      log.info("GlobalFilter 执行完成...");
    }
  }

  /**
   * 获取requestId.
   *
   * @param request HttpServletRequest
   * @return requestId
   */
  private String getOrSetRequestId(HttpServletRequest request) {
    // 先从 header 中获取requestId，如果获取不到则生成 requestId
    String requestId = request.getHeader(RequestEnum.REQUEST_ID.getCode());
    if (StringUtils.isBlank(requestId)) {
      requestId = UUID.randomUUID().toString().replace("-", "").substring(12);
      // 并将requestId放入request域中
      request.setAttribute(RequestEnum.REQUEST_ID.getCode(), requestId);
    }
    return requestId;
  }

  @Override
  public void destroy() {}
}
